#include <math.h>
#include <intrin.h>
#include <xmmintrin.h>

#include "syncommon.h"

Audio::DLS dls;

/* SYNTH DESIGN


PER VOICE
=================================

Note Number - Modulation input!
Velocity - Modulation input!
Pitch Wheel - Modulation input!
Modulation Wheel - mod input!

	OSC1
	OSC2
	OSC3
	  Mode: Sampler, Analog
		Sampler:
		  [ ] DLS instrument with region, color = region independent pitch shift
		Analog:
		  [ ] PWM - color = pulse width
		  [ ] Sine
		  [ ] Saw - color = morph to triangle
     Parameters:
	      [ ] Mode as described above
		  [ ] Wave speed multiplier (hardsync)
	      [ ] Color
		  [ ] Transpose
		  [ ] Detune
		  [ ] Volume
		  [ ] RingMod (OSC2,3 only)
		  [ ] FM (OSC2,3 only)

	LFO1 - Modulation input!
	LFO2
	  Modes:
		[ ] Sine
		[ ] Square
		[ ] Saw
		[ ] S&H
		[ ] S&H smooth
	  Parameters:
        [ ] Mode as described above
		[ ] Speed (as multiple of song tempo)
		[ ] Depth
	ENV1 - Modulation input!
	  [X] Hardwired to amp
    ENV2 - Modulation input!
	  Parameters:
	    [X] A D S R

	FILTER
	   [ ] Lo Hi BP BR 12db 24db? Vocal?

PER CHANNEL
===================================
    POLYPHONY
	   [ ] Max # voices
	   [ ] Slide speed

    DIST
	   [ ] Depth
	   [ ] Color
	   [ ] Type (ceil, fold, bitcrush, sample crush)

	FLANGER/CHORUS
       [ ] Time
	   [ ] Copies
	   [ ] Copy Spread

    AMP / SENDS
	   [ ] Final channel level
	   [ ] Reverb send
	   [ ] Global Delay send


PER SYNTH
===================================
    COMPRESSOR
	   [ ] Attack
	   [ ] Decay
	   [ ] Threshold
	   [ ] Ratio

    REVERB
	   [ ] Master level

	DELAY
       [ ] Delay Time
	   [ ] Amount
       [ ] Feedback Amount

    MASTER MIX
	   [ ] Master Level


*/

namespace Synth {

void Clear(Block buf) {
	__m128 zero = _mm_setzero_ps();
	for (int i = 0; i < BLOCKSIZE; i += 4) {
		float *ptr = &buf[i];
		_mm_store_ps(ptr, zero);  //buf[i] *= amount;
	}
}

void FixDenormals(Block buf) {
	FORBLOCK(i) {
		buf[i] += 0.0000001f;
	}
}

void Scale(Block buf, float amount) {
	__m128 scale = _mm_set1_ps(amount);
	for (int i = 0; i < BLOCKSIZE; i += 4) {
		float *ptr = &buf[i];
		_mm_store_ps(ptr, _mm_mul_ps(_mm_load_ps(ptr), scale));  //buf[i] *= amount;
	}
}

void AddScaled(Block dest, const Block src, float amount) {
	__m128 scale = _mm_set1_ps(amount);
	for (int i = 0; i < BLOCKSIZE; i += 4) {
		float *dptr = &dest[i];
		const float *sptr = &src[i];
		_mm_store_ps(dptr, _mm_add_ps(_mm_load_ps(dptr), _mm_mul_ps(_mm_load_ps(sptr), scale))); //		dest[i] += src[i] * scale;
	}
}

// Shay Green's approximation of a BLEP
// Kick ass! ?
void AddMinBLEPStep(float* out, int count, int oversample) {
	float maxh = 201; // keeps adjacent transitions from interfering
	for (float h = 1.0f; h <= maxh; h += 2.0f) {
		float rate = PI * h / (maxh * oversample);
		float x = (maxh - h) / (maxh - 1.0f); // goes from 1.0 to 0.0
		float curve = powf(x, 0.37f) - 1.0f;
		float phase = curve * 13.2f - oversample * rate;
		for (int i = 0; i < count; i++)
			out [i] += sin(i * rate + phase) / h;
	}
}

void PanVolume(Block lout, Block rout, Block lin, Block rin, float volume, float pan) {
	if (pan < 0.0f) pan = 0.0f;
	if (pan > 1.0f) pan = 1.0f;
	AddScaled(lout, lin, volume * sqrtf(1 - pan));
	AddScaled(rout, rin, volume * sqrtf(pan));
}

#ifndef STREAMLINED
const TCHAR *parameterNames[ParameterTableSize] = {
	//Affect each voice individually
	_T("---"), //Osc1Waveform
	_T("Osc1 InstrHardSync"),
	_T("Osc1 PulseWidth"),
	_T("Osc1 Transpose"),
	_T("Osc1 Detune"),
	_T("Osc1 Volume"),
	_T("!Osc1 FM"),
	_T("!Osc1 RingMod"),
	_T("Osc1 Pan"),
	_T("!Osc2 Waveform"),
	_T("-Osc2 InstrHardSync"),
	_T("Osc2 PulseWidth"),
	_T("Osc2 Transpose"),
	_T("Osc2 Detune"),
	_T("Osc2 Volume"),
	_T("Osc2 FM"),
	_T("Osc2 RingMod"),
	_T("Osc2 Pan"),
	_T("!Osc3 Waveform"), //20
	_T("-Osc3 InstrHardSync"),
	_T("Osc3 PulseWidth"),
	_T("Osc3 Transpose"),
	_T("Osc3 Detune"),
	_T("Osc3 Volume"),
	_T("Osc3 FM"),
	_T("Osc3 RingMod"),
	_T("Osc3 Pan"),
	_T("Voice Pitch"),
	_T("!LFO1 Waveform"),
	_T("-LFO1 Speed"),
	_T("!LFO1 Mode"),
	_T("LFO1 Phase"),
	_T("!LFO1 Sync"),
	_T("!LFO2 Waveform"),
	_T("LFO2 Speed"),
	_T("!LFO2 Mode"),
	_T("LFO2 Phase"),
	_T("!LFO2 Sync"),
	_T("-Env1 Attack"),
	_T("Env1 Decay"),
	_T("Env1 Sustain"), //40
	_T("Env1 Release"),
	_T("Env1 Amount"),
	_T("Env2 Attack"),
	_T("Env2 Decay"),
	_T("Env2 Sustain"),
	_T("Env2 Release"),
	_T("Env2 Amount"),
	_T("!Filter Type"),
	_T("-Filter Cutoff"),
	_T("Filter Resonance"),
	_T("-Dist PreGain"),
	_T("Dist Amount"),
	_T("Dist Color"),
	_T("!Dist Type"), //54	
	//Non-voice-specifics
	_T("!Polyphony"),
	_T("-Portamento Speed"),
    _T("!ChannelLFOWaveform"),
	_T("ChannelLFOSpeed"),
	_T("!ChannelLFOMode"),
	_T("-Channel Dist PreGain"),
	_T("Channel Dist Amount"),
	_T("Channel Dist Color"),
	_T("!Channel Dist Type"),
	_T("-ChannelFilter Type"),
	_T("ChannelFilter Cutoff"),
	_T("ChannelFilter Resonance"),
	_T("ChannelPhaser Amount"),
	_T("ChannelPhaser Frequency"),
	_T("ChannelPhaser Feedback"),
	_T("Channel Volume"),
	_T("!ChannelFXRouting"),
	_T("Channel Pan"),
	_T("Reverb Send"),
	_T("Delay Send"),
	_T("!Channel Bass Boost"),
	_T("!Channel Reserved"),
	_T("!Channel Compressor Mode"), //Off Peak RMS
	_T("-Channel Compressor Threshold"),
	_T("Channel Compressor Ratio"),
	_T("Channel Compressor Attack"),
	_T("Channel Compressor Release"),
	_T("Channel Compressor Makeup Gain"),
	_T("!Mod1Source"),
	_T("!Mod1Dest"),
	_T("!Mod1Amount"),
	_T("!Mod2Source"),
	_T("!Mod2Dest"),
	_T("!Mod2Amount"),
	_T("!Mod3Source"),
	_T("!Mod3Dest"),
	_T("!Mod3Amount"),
	_T("!Mod4Source"),
	_T("!Mod4Dest"),
	_T("!Mod4Amount"),
	_T("!Mod5Source"),
	_T("!Mod5Dest"),
	_T("!Mod5Amount"),
	_T("!Mod6Source"),
	_T("!Mod6Dest"),
	_T("!Mod6Amount"),
	_T("!Mod7Source"),
	_T("!Mod7Dest"),
	_T("!Mod7Amount"),
	_T("!Mod8Source"),
	_T("!Mod8Dest"),
	_T("!Mod8Amount"),
	_T("-Volume"),
	_T("ReverbVolume"),
	_T("ReverbLength"),
	_T("ReverbPole"),
	_T("DelayAmount"),
	_T("DelayPan"),
	_T("DelayFeedback"),
	_T("DelayLength"),
	_T("GlobalLowCut"),
	_T("GlobalHighCut"),
	_T("!CompressorMode"), //Off Peak RMS
	_T("CompressorThreshold"),
	_T("CompressorRatio"),
	_T("CompressorAttack"),
	_T("CompressorRelease"),
	_T("CompressorOutGain"),
	_T("Note"),
	_T("Velocity"),
	_T("LFO1"),
	_T("LFO2"),
	_T("Channel LFO"),
	_T("Env1"),
	_T("Env2"),
};
#endif
}

